/**
 * Proxy
 * 常用拦截方法
 */
// es5 代理
let obj = {}
let newName = ''
Object.defineProperty(obj, 'name', {
  get(){
    return newName
  },
  set(val){
    console.log('set')
    newName = val
  }
})

console.log(obj.name)
obj.name = '啊切'
console.log(obj.name)

// es6 proxy
let obj2 = {}
let p = new Proxy(obj2, {})
p.name = 'aqie'
console.log(obj2.name)

// get 钩子函数 : 监测数组指定下标是否有值，对数组代理
// set 钩子函数： 数组只接收数字
// has 判断是否存在 返回bool
let arr = [1,2,3]
arr = new Proxy(arr, {
  get(target, prop){
    console.log(target, prop) // [1, 2, 3] "1"
    return prop in target ? target[prop] : -1
  },
  set(target, prop, val){
    if(typeof val === 'number') {
      target[prop] = val
      return true
    } else{
      return false
    }
  }
})
console.log('数组第一个元素', arr[1])
arr[3] = 4
arr.push(3)
// arr.push('5')
arr.push(6)
console.log(arr)



// 实现字典: 对对象代理
/* let dict = {
  'hello':'你好',
  'world':'世界'
}

dict = new Proxy(dict, {
  get(target, prop) {
    return prop in target ? target[prop] : 'error'
  }
})

console.log(dict['hello'])
console.log(dict['hello1']) */

// has
/* let range = {
  start: 1,
  end:5
}
range = new Proxy(range, {
  has(target, prop){
    return  prop >= target.start && prop <= target.end
  }
})

console.log(2 in range) // true */

// ownKeys 对象循环遍历是拦截
let obj3 = {
  name: 'aqie',
  [Symbol('es')]:'es6'  // 变量加中括号
}

console.log(Object.getOwnPropertyNames(obj3))
console.log(Object.getOwnPropertySymbols(obj3))
console.log(Object.keys(obj3))
for(let key in obj3){
  console.log(key)
}

// 应用 : 保护私有属性不被遍历
let userInfo = {
  username:'aqie',
  age:18,
  _password: '888'
}
userInfo = new Proxy(userInfo, {
  get(target, prop){
    if(prop.startsWith('_')) {
      throw new Error('不可访问')
    } else {
      return target[prop]
    }
  },
  set(target, prop, val){
    if(prop.startsWith('_')){
      throw new Error('不可修改')
    }else{
      target[prop] = val
      return true
    }
  },
  deleteProperty(target, prop){ // 删除拦截
    if(prop.startsWith('_')){
      throw new Error('不可删除')
    }else{
      delete target[prop]
      return true
    }
  },
  ownKeys(target) {
    return Object.keys(target).filter(key => !key.startsWith('_'))
  }
})

for(let key in userInfo){
  console.log(key)
}

try {
  delete userInfo._password
  userInfo.name = 'bqie'
  userInfo._password = '111'
  console.log(userInfo.name,userInfo._password)
  
} catch (error) {
  console.log(error)
}

// apply 拦截函数调用 call  apply
let sum= (...arg) => {
  let num = 0
  arg.forEach(item => {
    num += item
  })
  return num
}

sum = new Proxy(sum, {
  // 目标 上下文 参数
  apply(target,ctx, args) {
    return target(...args) * 2
  }
})

console.log(sum(1,2))
console.log(sum.call(null, 1,2,3)) // call 改变this 指向
console.log(sum.apply(null, [1,2,3])) 

// construct 拦截 new 
let User = class {
  constructor(name){
    this.name = name
  }
}

User = new Proxy(User, {
  construct(target, args, newTarget){
    return new target(...args)
  }
})

console.log(new User('aqie'))
